#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/irq.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/fs.h> 
#include <linux/fcntl.h>
#include <linux/platform_device.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/i2c.h>

#define DEV_NAME "MyAp3216c"
#define DEV_NUM  1

struct ap3216c_dev_t
{
    char *name;                     //设备名
    int num;                    //设备数量
    dev_t ap3216c_devid;                //ap3216c设备号
    struct cdev ap3216c_cdev;	        //cdev结构体	    
	struct class *ap3216c_class;	    //ap3216c类
	struct device *ap3216c_device;	    //ap3216c设备
    struct file_operations fops;     //操作函数
    struct i2c_client *client;          //iic设备
};

struct ap3216c_dev_t ap3216c_dev;

static int i2c_readBytes(struct i2c_client *client,u8 reg, void *val, int len)
{
	int ret;
	struct i2c_msg msg[2];

	/* msg[0]为发送要读取的首地址 */
	msg[0].addr = client->addr;			/* ap3216c地址 */
	msg[0].flags = 0;					/* 标记为发送数据 */
	msg[0].buf = &reg;					/* 读取的首地址 */
	msg[0].len = 1;						/* reg长度*/

	/* msg[1]读取数据 */
	msg[1].addr = client->addr;			/* ap3216c地址 */
	msg[1].flags = I2C_M_RD;			/* 标记为读取数据*/
	msg[1].buf = val;					/* 读取数据缓冲区 */
	msg[1].len = len;					/* 要读取的数据长度*/

	ret = i2c_transfer(client->adapter, msg, 2);
	if(ret == 2) {
		ret = 0;
	} else {
		printk("i2c rd failed=%d reg=%06x len=%d\n",ret, reg, len);
		ret = -EREMOTEIO;
	}
	return ret;
}
static int i2c_writeBytes(struct i2c_client *client,u8 reg, u8 *val, int len)
{
    u8 b[256];
	struct i2c_msg msg;
	
	b[0] = reg;					/* 寄存器首地址 */
	memcpy(&b[1],val,len);		/* 将要写入的数据拷贝到数组b里面 */
		
	msg.addr = client->addr;	/* ap3216c地址 */
	msg.flags = 0;				/* 标记为写数据 */

	msg.buf = b;				/* 要写入的数据缓冲区 */
	msg.len = len + 1;			/* 要写入的数据长度 */

	return i2c_transfer(client->adapter, &msg, 1);
}
static int i2c_readOneByte(struct i2c_client *client,u8 reg, u8 *data)
{
	i2c_readBytes(client, reg, data, 1);
    return 0;
}
static int i2c_writeOneByte(struct i2c_client *client,u8 reg, u8 data)
{
    u8 buf = 0;
	buf = data;
	i2c_writeBytes(client, reg, &buf, 1);
    return 0;
}
static int ap3216c_open(struct inode *inode, struct file *filp)
{
    /* 初始化AP3216C */
	i2c_writeOneByte(ap3216c_dev.client, 0x00, 0x04);		/* 复位AP3216C 			*/
	mdelay(50);														/* AP3216C复位最少10ms 	*/
	i2c_writeOneByte(ap3216c_dev.client, 0x00, 0X03);		/* 开启ALS、PS+IR 		*/
    printk("The Ap3216c is opened!\r\n");
	return 0;
}
static ssize_t ap3216c_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
{
    long err = 0;
    u8 _buf[6];
    short data[3];
    int i=0;
    for(i=0;i<6;i++)
    {
        i2c_readOneByte(ap3216c_dev.client,0x0A+i, &_buf[i]);
    }

    if(_buf[0] & 0X80)
    {
        data[0] = 0;
    }
    else
    {
        data[0] = ((unsigned short)_buf[1] << 2) | (_buf[0] & 0X03); 
    }
    data[1] = ((unsigned short)_buf[3] << 8) | _buf[2];	/* 读取ALS传感器的数据 			 */  
    if(_buf[4] & 0x40)
    {
        data[2] = 0;
    }
    else
    {
        data[2] = ((unsigned short)(_buf[5] & 0X3F) << 4) | (_buf[4] & 0X0F); 
    }
    err = copy_to_user(buf, data, sizeof(data));
	return 0;
}
static int ap3216c_release(struct inode *inode, struct file *filp)
{
    return 0;
}
static int ap3216c_probe(struct i2c_client *client,const struct i2c_device_id *device_id)
{
    /*
    .定义操作函数
    .定义设备结构体
    .申请设备号
    .绑定字符设备和操作函数
    .绑定字符设备和设备号
    .创建类,设备
    */

    //IIC设备结构体
    ap3216c_dev.client = client;

    //填充fops结构体
    ap3216c_dev.fops.owner = THIS_MODULE;
    ap3216c_dev.fops.open = ap3216c_open;
    ap3216c_dev.fops.read = ap3216c_read;
    ap3216c_dev.fops.release = ap3216c_release;

    //申请设备号
    ap3216c_dev.name = DEV_NAME;
    ap3216c_dev.num = DEV_NUM;
    alloc_chrdev_region(&ap3216c_dev.ap3216c_devid,0,ap3216c_dev.num,ap3216c_dev.name);

    //绑定cdev结构体和文件操作集合
    ap3216c_dev.ap3216c_cdev.owner = THIS_MODULE;
    cdev_init(&ap3216c_dev.ap3216c_cdev,&ap3216c_dev.fops);

    //绑定cdev结构体和设备号
    cdev_add(&ap3216c_dev.ap3216c_cdev,ap3216c_dev.ap3216c_devid,ap3216c_dev.num);

    //创建类和设备
    ap3216c_dev.ap3216c_class = class_create(THIS_MODULE,ap3216c_dev.name);        //创建类
    ap3216c_dev.ap3216c_device = device_create(ap3216c_dev.ap3216c_class, NULL, ap3216c_dev.ap3216c_devid, NULL, ap3216c_dev.name);//创建设备

    printk("Adder:%02x\r\n",client->addr);
    return 0;
}
static int ap3216c_remove(struct i2c_client *client)
{
    return 0;
}
/* 传统匹配方式ID列表 */
static const struct i2c_device_id ap3216c_id[] = {
	{"alientek,ap3216c", 0},  
	{}
};
static struct of_device_id IIC_of_match[] = 
{
    {.compatible = "MyAp3216cDriver"},
    { /* Sentinel */ }
};
static struct i2c_driver ap3216c_driver = {
    .driver		= {
        .owner = THIS_MODULE,
		.name	= "MyAp3216cDriver111",			/* 驱动名字，用于和设备匹配 */
		.of_match_table	= IIC_of_match,     /* 设备树匹配表，用于和设备匹配*/
	},
    .id_table = ap3216c_id,
	.probe		= ap3216c_probe,
	.remove		= ap3216c_remove,
};
static int __init ap3216c_Init(void)
{
    int ret = 0;
    printk("Begin Init...\r\n");
	ret = i2c_add_driver(&ap3216c_driver);
    // printk("ret:%d\r\n",ret);
	return ret;
}
static void __exit ap3216c_Exit(void)
{
    i2c_del_driver(&ap3216c_driver);
}

module_init(ap3216c_Init);
module_exit(ap3216c_Exit);
MODULE_AUTHOR("ZiXie");
MODULE_LICENSE("GPL");